using PKGames.Plugins.Crashlytics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
using VoxelGame;

namespace PKGames.SceneManagement
{
	public class SceneLoader : MonoSingleton<SceneLoader>
	{
		[SerializeField]
		private TransitionController _transitionController;

		protected Stack<string> _sceneHistory;

		public Action OnPKGamesContextFinished;

		private bool _finishingContext;

		private bool _isInSceneTransition;

		protected override void Awake()
		{
			base.Awake();
			_sceneHistory = new Stack<string>();
		}

		public void ClearHistory()
		{
			_sceneHistory.Clear();
		}

		protected void PushSceneHistory(string scene)
		{
			if (_sceneHistory.IsNullOrEmpty() || _sceneHistory.First() != scene)
			{
				_sceneHistory.Push(scene);
			}
		}

		public void GotoPreviousScene(Action onFinish = null)
		{
			StartCoroutine(GotoPreviousSceneAsync(onFinish));
		}

		private IEnumerator GotoPreviousSceneAsync(Action onFinish = null)
		{
			if (!_sceneHistory.IsNullOrEmpty())
			{
				_sceneHistory.Pop();
			}
			if (!_sceneHistory.IsNullOrEmpty())
			{
				yield return LoadSubSceneAsync(_sceneHistory.First(), storeInSceneHistory: false);
			}
			else
			{
				yield return FinishPKGamesContext();
			}
			onFinish.Fire();
		}

		public IEnumerator FinishPKGamesContext()
		{
			WorldSelectionController.IsExplorerPainter = false;
			yield return FinishPKGamesContextAsync();
		}

		private IEnumerator FinishPKGamesContextAsync()
		{
			_finishingContext = true;
			AsyncOperation loadSceneOperation = SceneManager.LoadSceneAsync(GetMainScene());
			while (!loadSceneOperation.isDone)
			{
				yield return null;
			}
			OnPKGamesContextFinished.Fire();
			_finishingContext = false;
		}

		private string GetMainScene()
		{
			return "VoxelPlayerWorldSelector";
		}

		public void LoadSubScene(string scene, bool storeInSceneHistory = true, bool isAdditive = false)
		{
			StartCoroutine(LoadSubSceneAsync(scene, storeInSceneHistory, isAdditive));
		}

		public IEnumerator LoadSubSceneAsync(string scene, bool storeInSceneHistory = true, bool isAdditive = false)
		{
			if (!_isInSceneTransition)
			{
				_isInSceneTransition = true;
				yield return _transitionController.FadeIn(() => LoadSubSceneInternal(scene, storeInSceneHistory, isAdditive), scene);
				_isInSceneTransition = false;
			}
		}

		private IEnumerator LoadSubSceneInternal(string scene, bool storeInSceneHistory = true, bool isAdditive = false)
		{
			yield return LoadSceneAsync(scene, storeInSceneHistory, isAdditive);
		}

		private IEnumerator LoadSceneAsync(string scene, bool storeInSceneHistory = true, bool isAdditive = false)
		{
			UnityEngine.Debug.Log("[SceneLoader] LoadSceneAsync: " + scene);
			LogAppNavigation(scene);
			while (_finishingContext)
			{
				UnityEngine.Debug.Log("[SceneLoader] Waiting For context to finish...");
				yield return null;
			}
			if (storeInSceneHistory)
			{
				PushSceneHistory(scene);
			}
			AsyncOperation loadSceneOperation = (!isAdditive) ? SceneManager.LoadSceneAsync(scene) : SceneManager.LoadSceneAsync(scene, LoadSceneMode.Additive);
            //loadSceneOperation.allowSceneActivation = true;
			while (!loadSceneOperation.isDone)
			{
				yield return null;
			}
			yield return _transitionController.FadeOut(OnSceneLoaded);
		}

		private void LogAppNavigation(string scene)
		{
			CrashlyticsPluginFactory.Create().Log("Loaded scene", scene);
		}

		private IEnumerator OnSceneLoaded()
		{
			yield return null;
		}

		public void Update()
		{
		}

		public void OnApplicationPause(bool pauseStatus)
		{
			if (_sceneHistory != null && _sceneHistory.Count >= 1)
			{
				string tag = (!pauseStatus) ? "Unpause scene" : "Pause scene";
				CrashlyticsPluginFactory.Create().Log(tag, _sceneHistory.First());
			}
		}
	}
}
